//
//  FileURLGenerator.swift
//
//  Created by Evan Xie on 2018/5/27.
//

import Foundation

/** Descrbing the number output format. */
public enum NumberOutputFormat {
    /// The default behavior. eg, number 8 => 8, number 19 => 19.
    case nature
    
    /// Using a fixed width to output number. eg. we use fixWidth(3), then number 8 => 008,
    /// number 19 => 019, number 119 => 119, number 1191 => 1191.
    case fixedWidth(Int)
}

public class FileURLGenerator {
    
    public struct Config {
        let referredFileURL: URL
        
        /// The output format for sequential number.
        let sequentialNumberFormat: NumberOutputFormat
        
        /// Used for connecting original file name and sequential number.
        let boundSymbol: String
        
        let startSequenceNumber: Int
        
        public init(
            referredFileURL: URL,
            sequentialNumberFormat: NumberOutputFormat = .nature,
            boundSymbol: String = " ",
            startSequenceNumber: Int = 1
        ) {
            self.referredFileURL = referredFileURL
            self.sequentialNumberFormat = sequentialNumberFormat
            self.boundSymbol = boundSymbol
            self.startSequenceNumber = startSequenceNumber
        }
    }
    
    public init(config: Config) {
        self.config = config
    }
    
    public func nextFileURL(withPathExtension ext: String) -> URL {
        
        let parentURL = config.referredFileURL.deletingLastPathComponent()
        let lastPathComponent = config.referredFileURL.lastPathComponent as NSString
        let name = lastPathComponent.deletingPathExtension
        let numberFormatStr = numberFormatString(from: config.sequentialNumberFormat)
        var pathExtension = ext
        
        // If give path extension is empty, use the referred file url path extension.
        if ext.trimmingCharacters(in: .whitespacesAndNewlines).lengthOfBytes(using: .utf8) == 0 {
            pathExtension = lastPathComponent.pathExtension
        }
        
        var sequenceNumber = config.startSequenceNumber
        var url = composeURL(with: parentURL, numberFormatString: numberFormatStr, fileName: name,
                             fileExtension: pathExtension, boundSymbol: config.boundSymbol, sequenceNumber: sequenceNumber)
        
        while FileManager.default.fileExists(atPath: url.path) {
            sequenceNumber += 1
            url = composeURL(with: parentURL, numberFormatString: numberFormatStr, fileName: name,
                             fileExtension: pathExtension, boundSymbol: config.boundSymbol, sequenceNumber: sequenceNumber)
        }
        
        return url
    }
    
    public func resetConfig(_ config: Config) {
        self.config = config
    }
    
//    public func isSameGenerationRules(forFileURL fileURL: URL) -> Bool {
//
//        let parentURL = config.referredFileURL.deletingLastPathComponent()
//        guard fileURL.deletingLastPathComponent() == parentURL else { return false }
//
//        let ruledFileName = (config.referredFileURL.lastPathComponent as NSString).deletingPathExtension
//        let ruledFileExtension = config.referredFileURL.pathExtension
//
//        let givenFileName = (fileURL.lastPathComponent as NSString).deletingPathExtension
//        let givenFileExtension = fileURL.pathExtension
//
//        guard givenFileName.hasPrefix(ruledFileName), ruledFileExtension == givenFileExtension else {
//            return false
//        }
//
//        // Extra part is composed with bound symbol and sequence number.
//        let extraPart = givenFileName.replacingOccurrences(of: ruledFileName, with: "")
//        if !config.boundSymbol.isEmpty {
//            let symbolLength = config.boundSymbol.lengthOfBytes(using: .utf8)
//            guard extraPart.split(separator: <#T##Character#>) == config.boundSymbol else {
//                // The give file name doesn't have the same bound symbol with the ruled file name.
//                return false
//            }
//        }
//
//    }
    
    private var config: Config
}

fileprivate extension FileURLGenerator {
    
    func numberFormatString(from outputFormat: NumberOutputFormat) -> String{
        switch outputFormat {
        case .nature:
            return "%d"
        case let .fixedWidth(width):
            return "%0\(width)d"
        }
    }
    
    func composeURL(with parentURL: URL,
                                numberFormatString: String,
                                fileName: String,
                                fileExtension: String,
                                boundSymbol: String,
                                sequenceNumber: Int) -> URL {
        
        var newPathComponent = String(format: "%@%@\(numberFormatString)", fileName, boundSymbol, sequenceNumber)
        if !fileExtension.isEmpty {
            newPathComponent = (newPathComponent as NSString).appendingPathExtension(fileExtension)!
        }
        return parentURL.appendingPathComponent(newPathComponent)
    }
}
